package vip.george.sentinel1.controller;

import com.alibaba.csp.sentinel.Entry;
import com.alibaba.csp.sentinel.EntryType;
import com.alibaba.csp.sentinel.SphU;
import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.alibaba.csp.sentinel.slots.block.RuleConstant;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRule;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRuleManager;
import com.alibaba.csp.sentinel.slots.block.degrade.circuitbreaker.CircuitBreakerStrategy;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRule;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager;
//import jakarta.annotation.PostConstruct;
import org.springframework.web.bind.annotation.*;
import vip.george.common.dto.ResultVO;

import javax.annotation.PostConstruct;
import java.util.ArrayList;
import java.util.List;

/**
 * @author george
 * @since 2023/7/7
 * <p></p>
 */

@RestController
@RequestMapping("/sentinel")
public class SentinelController {

    /**
     * 流控规则演示资源名称
     */
    private final static String flowRuleTest = "flowRuleTest";

    /**
     * 熔断降级规则演示资源名称
     */
    private final static String degradeRuleTest = "degradeRuleTest";

    /**
     * bean创建的时候就设置流控规则
     */
    @PostConstruct
    public void initFlowRules(){
        List<FlowRule> rules = new ArrayList<>();
        FlowRule rule = new FlowRule();
        rule.setResource(flowRuleTest);
        rule.setGrade(RuleConstant.FLOW_GRADE_QPS);
        // 设置请求限制，每秒最多请求一次
        rule.setCount(1);
        rules.add(rule);
        FlowRuleManager.loadRules(rules);
    }


    /**
     * 熔断降级规则设置
     */
    @PostConstruct
    public void initDegradeRules(){
        List<DegradeRule> rules = new ArrayList<>();
        DegradeRule rule = new DegradeRule();
        rule.setResource(degradeRuleTest);
        //设置熔断策略：异常数策略
        rule.setGrade(CircuitBreakerStrategy.ERROR_COUNT.getType());
        // 设置阈值（执行熔断的异常数）
        rule.setCount(2);
        // 熔断请求的最小请求数
        rule.setMinRequestAmount(2);
        // 熔断的统计时长
        rule.setStatIntervalMs(60 * 1000);
        // 单次熔断的持续时间
        rule.setTimeWindow(10);

        //综上：
        //熔断的条件是： 60s内，使用该规则的资源发生大于3次的异常，就会发生熔断，熔断时间持续10s
        //注意，当熔断时间结束后的第一次请求如果是异常，则直接再次熔断，不会判断是否达到阈值条件
        rules.add(rule);
        DegradeRuleManager.loadRules(rules);
    }


     /**
     * 流控测试
     */
    @PostMapping("/flowTest")
    public ResultVO<String> alipay(){
        try(Entry entry = SphU.entry(flowRuleTest)) {
            return  ResultVO.success("pay success");
        } catch (BlockException e) {
            //被流控时抛出异常，下面是被流控时的异常处理逻辑
            System.out.println("请求失败，接口资源被流控");
            return ResultVO.error("500","request limit!!");
        }
    }


    /**
     * 熔断降级测试
     * @return
     */
    @GetMapping("/degradeTest")
    @SentinelResource(value = degradeRuleTest, entryType = EntryType.IN,blockHandler = "degradeHandler")
    public ResultVO<String> payCallback(){

        //手动制造异常
        int a = 1/0;
        return ResultVO.success("success");
    }

    /**
     * 指定熔断降级执行的方法
     */
    public ResultVO<String> degradeHandler(BlockException ex){
        System.out.println("执行熔断降级的方法");
        ex.printStackTrace();
        return ResultVO.error("被熔断降级");

    }
}
